# coding=utf-8
import os
import re

PACKAGE = "tungsten.pb.module"
BASE_MODULE_IMPORT = ["import com.google.protobuf.Message;","import tungsten.base.server.BaseClient;","import tungsten.pb.protocol.*;"]
MODULE_IMPORT = ["import tungsten.base.server.BaseClient;","import tungsten.pb.PBAnnotation;","import tungsten.pb.protocol.*;"];
class Message:
    def __init__(self):
        self.lines = []
        self.messageName = None
        self.children = []
        self.state = 0 # 0 not begin   1  find the end
        self.type = None


    def eat_line(self,lines):
        while len(lines) > 0:
            line = lines.pop(0)
            line = line.strip()
            title = None
            if line.startswith("message"):
                title = "message"
            elif line.startswith("enum"):
                title = "enum"
            elif line.startswith("oneof"):
                title = "oneof"

            if title is not None:
                if self.state == 0:
                    match = re.match(title + ' (\w+)',line)
                    self.messageName = match.group(1)
                    self.state = 1
                    self.type = title
                    self.lines.append(line)
                else:
                    lines.insert(0,line)
                    message = Message().eat_line(lines)
                    self.children.append(message)
                    self.lines.extend(message.lines)
            if line.count("}") > 0 :
                if self.state == 1:
                    self.state = 2
                    self.lines.append(line)
                    break
                else:
                    raise "something wrong!"
            else:
                if self.state == 1 and title is None:
                    self.lines.append(line)
        return self


class ProtoFile:
    def __init__(self, path):
        self.path = path
        self.fold, self.file = os.path.split(path)
        self.fileName, _ = self.file.split(".")
        self.baseName = self.__get_base_module_name()
        self.moduleName = self.__get_module_name()
        self.className = self.fileName
        self.fileData = None
        self.messages = []
        self.req = "Req"
        self.is_export = False
        self.req_list = []

        with open(self.path,"r") as fl:
            self.fileData = fl.read()

        lines = self.fileData.split("\n")

        while len(lines) > 0 :
            line = lines.pop(0)
            line = line.strip()
            title = None
            if line.startswith("message"):
                title = "message"
            elif line.startswith("enum"):
                title = "enum"
            elif line.startswith("oneof"):
                title = "oneof"
            elif line.startswith("option java_outer_classname"):
                match = re.match("option java_outer_classname *=(.*?);", line)
                group = match.group(1).strip()
                group = group[1:-1]
                self.className = group

            if title is not None:
                lines.insert(0,line)
                self.messages.append(Message().eat_line(lines))

        for message in self.messages:
            if message.messageName == self.req:
                body = message.children[0]
                for line in body.lines:
                    line = line.strip()
                    if line.startswith("//"): continue
                    match = re.match("(\w+) (\w+) *=.*?;", line)
                    if match is not None:
                        self.req_list.append([match.group(1), match.group(2)])
                break
            elif message.messageName == "ModuleType":
                self.is_export = True

            if self.is_export and len(self.req_list) > 0:
                break

    def export(self):
        __export = self.is_export
        __req = self.req_list

        if not __export or len(__req) == 0:return

        lines = []
        lines.append("package " + PACKAGE + ";")
        lines.extend(BASE_MODULE_IMPORT)

        lines.append("")

        lines.append("public class " + self.baseName + " extends Module")
        lines.append("{")
        lines.append("\tpublic " + self.baseName + "()")
        lines.append("\t{")
        lines.append("\t\tsuper(" + self.className + "."+self.req+".getDefaultInstance().getParserForType());")
        lines.append("\t}")

        lines.append("")

        lines.append("\t@Override")
        lines.append("\tprotected void onMessage(BaseClient client,Heads.Head head,Message absMsg)")
        lines.append("\t{")
        lines.append("\t\t" + self.className + "."+self.req+" message = (" + self.className + "."+self.req+") absMsg;")
        lines.append("\t\tswitch(message.getBodyCase())")
        lines.append("\t\t{")
        lines.extend(self.__get__message("\t\t\t",__req))
        lines.append("\t\t}")
        lines.append("\t}")
        lines.append("")

        for req in __req :
            lines.extend(self.__get__func("\t",*req))

        lines.append("}")

        fileData = "\n".join(lines)
        with open(os.path.join(self.__get__export_path(),self.__get_base_module_name() + ".java"),"w") as fl:
            fl.write(fileData)

        module_file = os.path.join(self.__get__export_path(),self.__get_module_name() + ".java");
        if not os.path.exists(module_file):
            self.__export_module(module_file,__req)

    def __export_module(self,module_file,req):

        lines = []
        lines.append("package " + PACKAGE + ";")
        lines.extend(MODULE_IMPORT)

        lines.append("")

        lines.append("@PBAnnotation(module = " + self.className + ".ModuleType.TYPE_FIELD_NUMBER,desc = \"\")")
        lines.append("public class " + self.moduleName + " extends " + self.baseName)
        lines.append("{")
        lines.append("\t")
        lines.append("}")

        with open(module_file,"w") as fl:
            fl.write("\n".join(lines))

    def __get_base_module_name(self):
        return "Base" + self.fileName + "Module"

    def __get_module_name(self):
        return self.fileName + "Module"

    def __get__export_path(self):
        return os.path.join(os.path.split(self.fold)[0],"src","main","java",*PACKAGE.split("."))

    def __get__message(self, tab,req):
        lines = []
        for _,line in req:
            c_line = line[0].upper() + line[1:]
            lines.append(tab + "case " + line.upper() + ":on" + c_line + "(client,head,message.get" + c_line + "());break;")
        return lines

    def __get__func(self, tab, param,func):
        lines = []
        c_line = func[0].upper() + func[1:]
        lines.append(tab + "protected void on" + c_line + "(BaseClient client,Heads.Head head," + self.className + "." + param + " " + func + "){}")
        return lines


if __name__ == '__main__':
    files = [os.path.join(os.path.split(__file__)[0], name) for name in os.listdir(os.path.split(__file__)[0]) if
             name.split(".")[1] == "proto"]
    for fileName in files:
        fold = os.path.split(fileName)[0]
        root = os.path.join(os.path.split(fold)[0],"src","main","java")
        os.system("protoc.exe --java_out=" + root + " " + os.path.split(fileName)[1])
        ProtoFile(fileName).export()
